import { Injectable } from '@angular/core';
import { ModalOptions, NzModalRef, NzModalService } from 'ng-zorro-antd/modal';
import { NzSafeAny } from 'ng-zorro-antd/core/types';

@Injectable({
	providedIn: 'root',
})
export class DragModalService extends NzModalService {
	private canMove = false;
	private mouseDownX = 0;
	private mouseDownY = 0;
	private modalX = 0;
	private modalY = 0;
	private listens = [];

	createDrag<T, D = NzSafeAny, R = NzSafeAny>(config: ModalOptions<T, D, R>): NzModalRef<T, R> {
		const refModal = super.create({
			nzFooter: null,
			nzMaskClosable: false,
			...config,
		});
		const modalBackground = refModal.containerInstance.modalElementRef.nativeElement;
		const modalElement = refModal.containerInstance.modalElementRef.nativeElement.querySelector('.ant-modal-content');
		const modalTitleElement = this.createModalTitleElement(modalElement);
		this.dragListen(modalTitleElement, modalElement, modalBackground);
		return refModal;
	}

	private createModalTitleElement(modalElement) {
		let element = document.createElement('div') as HTMLDivElement;
		this.setStyle(element, 'width', '100%');
		this.setStyle(element, 'height', '54px');
		this.setStyle(element, 'position', 'absolute');
		this.setStyle(element, 'top', '0');
		this.setStyle(element, 'left', '0');
		this.setStyle(element, 'cursor', 'move');
		this.setStyle(element, '-moz-user-select', 'none');
		this.setStyle(element, '-webkit-user-select', 'none');
		this.setStyle(element, '-ms-user-select', 'none');
		this.setStyle(element, '-khtml-user-select', 'none');
		this.setStyle(element, 'user-select', 'none');
		this.appendChild(modalElement, element);
		return element;
	}

	private dragListen(modalTitleElement, modalElement, modalBackground) {
		this.listen(modalTitleElement, 'mousedown', (event) => {
			this.mouseDownX = event.clientX;
			this.mouseDownY = event.clientY;
			this.modalX = modalElement.offsetLeft;
			this.modalY = modalElement.offsetTop;
			this.setStyle(modalElement, 'left', `${this.modalX}px`);
			this.setStyle(modalElement, 'top', `${this.modalY}px`);
			this.canMove = true;
		});
		this.listen(modalTitleElement, 'mouseup', (event) => {
			this.canMove = false;
		});
		this.listen(modalBackground, 'mousemove', (event) => {
			if (this.canMove) {
				let moveX = event.clientX - this.mouseDownX;
				let moveY = event.clientY - this.mouseDownY;
				let newModalX = this.modalX + moveX;
				let newModalY = this.modalY + moveY;
				this.setStyle(modalElement, 'left', `${newModalX}px`);
				this.setStyle(modalElement, 'top', `${newModalY}px`);
			}
		});
	}

	private setStyle(element, key, value) {
		element.style[key] = value;
	}

	private appendChild(p, e) {
		p.appendChild(e);
	}

	private listen(el: HTMLElement, ev, bc) {
		el.addEventListener(ev, bc);
		this.listens.push({
			el,
			ev,
			bc,
		});
	}

	override ngOnDestroy() {
		this.listens.forEach(({ el, ev, bc }) => {
			el.removeEventListener(ev, bc);
		});
		super.ngOnDestroy();
	}
}
